﻿using Nemerle.Text;
using Nemerle.Utility;

using System;
using System.Collections.Generic;
using System.Linq;

namespace Nemerle.Data
{
  
  #warning not tested
  [Record]
  internal class ArrayMapIterator[From, To] : Seq[To], IFunctor[To], ILeftFoldable[To], IRightFoldable[To]
  {
    private _array : array[From];
    private _f : From -> To;
    
    public GetEnumerator() : IEnumerator[To]
    {
      foreach(x in _array) yield _f(x) 
    }
    
    //private IEnumerable.GetEnumerator() : IEnumerator
    //{
    //  (_array : IEnumerable).GetEnumerator() 
    //}
    
    public Map[To2](f : To -> To2) : Seq[To2]
    {
      ArrayMapIterator(_array, _f >> f)
    }
    
    #warning TO DO проблема с Map и MapI в одном интерфейсе? Нет, просто добавить еще один итератор - индексированный.
    public MapI[To2](f : int * To -> To2) : Seq[To2]
    {
      null
    }
    
    public FoldLeft[TAccumulator]( 
      mutable init : TAccumulator,
      f : TAccumulator * To -> TAccumulator
    ) : TAccumulator
    {
      foreach(x in _array) init = f(init, _f(x));
      init
    }
    
    public ReduceLeft(f : To * To -> To) : To
    {
      mutable acc = _f(_array[0]);
      foreach (i in [1.._array.Length-1])
        acc = f(acc, _f(_array[i]));
      acc 
    }

    public FoldLeftI[TAccumulator]( 
      mutable init : TAccumulator,
      f : int * TAccumulator * To -> TAccumulator
    ) : TAccumulator
    {
      foreach(x in _array with i) 
        init = f(i, init, _f(x));
      init
    }
    
    #warning TO DO
    public FoldRight[TAccumulator]( 
      init : TAccumulator,
      f : To * TAccumulator -> TAccumulator
    ) : TAccumulator
    {
      init
    }
    
    #warning TO DO
    public ReduceRight(f : To * To -> To) : To
    {
      default(To)
    }
    
    #warning TO DO
    public FoldRightI[TAccumulator]( 
      init : TAccumulator,
      f : int * To * TAccumulator -> TAccumulator
    ) : TAccumulator
    {
      init
    }
  }
}
